using System;
using System.Linq;
using NUnit.Framework;
using OpenWaves.ActivityFeed.UnitTests.Web;
using OpenWaves.ActivityFeed.Web;
using OpenWaves.ActivityFeed.Web.Modules;

namespace OpenWaves.ActivityFeed.UnitTests
{
    public abstract class UpdatesBuilderTests : ActivityFeedServiceTestsBase
    {
        protected UpdateDtoBuilder updateDtoBuilder;

        [SetUp]
        public void Initialize()
        {
            updateDtoBuilder = new UpdateDtoBuilder(UserProfileProviderMockFactory.GetSimpleMock().Object);
        }

        protected static void CreateUpdates(IActivityFeedService service)
        {
            using (var fakeTime = FakeTimeScope.Begin())
            {
                fakeTime.Now = new DateTime(2012, 01, 01);
                service.PublishUpdate(new Post("update1"), "user1111", "source", Enumerable.Empty<Topic>(), true,
                                      Enumerable.Empty<UserGroup>());
                fakeTime.Now = new DateTime(2012, 01, 02);
                service.PublishUpdate(new Post("update2"), "user1111", "source", Enumerable.Empty<Topic>(), true,
                                      Enumerable.Empty<UserGroup>());
                fakeTime.Now = new DateTime(2012, 01, 03);
                service.PublishUpdate(new Post("update22"), "user1111", "source", Enumerable.Empty<Topic>(), true,
                                      Enumerable.Empty<UserGroup>());
                fakeTime.Now = new DateTime(2012, 01, 04);
                service.PublishUpdate(new Post("update3"), "user1111", "source", new Topic[] { Topic.FromUserId("john") }, true,
                                      Enumerable.Empty<UserGroup>());
                fakeTime.Now = new DateTime(2012, 01, 05);
                service.PublishUpdate(new Post("update4"), "user1111", "source", new Topic[] { Topic.FromUserId("sam") }, true,
                                      Enumerable.Empty<UserGroup>());
                fakeTime.Now = new DateTime(2012, 01, 06);
                service.PublishUpdate(new Post("update5"), "user1111", "source", Enumerable.Empty<Topic>(), true,
                                      Enumerable.Empty<UserGroup>());
            }
        }

        [Test]
        public void Given_test_updates_When_pageSize_is_assigned_Then_GetUpdates_returns_limited_list_of_updates()
        {
            var pageSize = 1;

            Given(CreateUpdates);

            this.Then(service =>
                     {
                         ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                         activityFeedBuilder.PaginationRequest = new PaginationRequest() {PageSize = pageSize};
                         activityFeedBuilder.SearchTerms = "";
                         activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                         activityFeedBuilder.TopicsFilter = Enumerable.Empty<Topic>();
                         PaginationStatus status;
                         var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                         Assert.That(updates.Count, Is.EqualTo(1));
                         Assert.That(((Post) updates[0].Content).Text, Is.EqualTo("update5"));
                     });
        }

        [Test]
        public void Given_test_updates_When_DateFrom_is_assigned_Then_GetUpdates_returns_limited_list_of_updates()
        {
            var dateFrom = new DateTime(2012, 01, 02);

            Given(CreateUpdates);

            this.Then(service =>
                     {
                         ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                         activityFeedBuilder.PaginationRequest = new PaginationRequest() {PageSize = 500, DateFrom = dateFrom};
                         activityFeedBuilder.SearchTerms = "";
                         activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                         activityFeedBuilder.TopicsFilter = Enumerable.Empty<Topic>();
                         PaginationStatus status;
                         var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                         Assert.That(updates.Count, Is.EqualTo(1));
                         Assert.That(((Post) updates[0].Content).Text, Is.EqualTo("update1"));
                     });
        }

        [Test]
        public void Given_test_updates_When_roles_are_assigned_Then_GetUpdates_returns_limited_list_of_updates()
        {
            var dateFrom = new DateTime(2012, 01, 02);

            Given(CreateUpdates);

            this.Then(service =>
                     {


                         ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                         activityFeedBuilder.PaginationRequest = new PaginationRequest() {PageSize = 500, DateFrom = dateFrom};
                         activityFeedBuilder.SearchTerms = "";
                         activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                         activityFeedBuilder.TopicsFilter = Enumerable.Empty<Topic>();
                         PaginationStatus status;
                         var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                         Assert.That(updates.Count, Is.EqualTo(1));
                         Assert.That(((Post) updates[0].Content).Text, Is.EqualTo("update1"));
                     });
        }

        [Test]
        public void Given_test_updates_When_there_is_more_than_pageSize_of_updates_Then_PaginationStatus_PartialResult_is_returned()
        {
            var dateFrom = Time.Now;

            Given(CreateUpdates);

            this.Then(service =>
                     {


                         ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                         activityFeedBuilder.PaginationRequest = new PaginationRequest() {PageSize = 3, DateFrom = dateFrom};
                         activityFeedBuilder.SearchTerms = "";
                         activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                         activityFeedBuilder.TopicsFilter = Enumerable.Empty<Topic>();
                         PaginationStatus status;
                         var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                         Assert.That(status, Is.EqualTo(PaginationStatus.PartialResults));
                     });
        }

        [Test]
        public void Given_test_updates_When_there_is_more_than_pageSize_of_updates_Then_PaginationStatus_CompleteResult_is_returned()
        {
            var dateFrom = Time.Now;

            Given(CreateUpdates);

            this.Then(service =>
            {


                ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                activityFeedBuilder.PaginationRequest = new PaginationRequest() { PageSize = 100, DateFrom = dateFrom };
                activityFeedBuilder.SearchTerms = "";
                activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                activityFeedBuilder.TopicsFilter = Enumerable.Empty<Topic>();
                PaginationStatus status;
                var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                Assert.That(status, Is.EqualTo(PaginationStatus.CompleteResults));
            });
        }        

        [Test]
        public void Given_test_updates_then_PublishedWithinTimeRange_returns_updates_between_specified_dates()
        {
            const string firstPublisher = "1";
            const string anotherPublisher = "2";

            var startDate = new DateTime(2001, 1, 1);

            Given(service =>
                {
                    using (var fakeTime = FakeTimeScope.Begin(startDate))
                    {
                        service.PublishPublicUpdate(new Post("post1"), firstPublisher, "web");
                        fakeTime.Forward(TimeSpan.FromDays(1));
                        service.PublishPublicUpdate(new Post("post1"), firstPublisher, "web");
                        service.PublishPublicUpdate(new Post("post2"), firstPublisher, "web");
                        fakeTime.Forward(TimeSpan.FromDays(1));
                        service.PublishPublicUpdate(new Post("last post"), anotherPublisher, "web");
                    }
                });

            Then(service =>
                {
                    var updates = service.GetUpdates()
                                         .PublishedWithinTimeRange(startDate, startDate.AddMinutes(1.0));
                                         
                    Assert.That(updates.Count(), Is.EqualTo(1));

                    updates = service.GetUpdates().PublishedWithinTimeRange(startDate, startDate.AddDays(1));

                    Assert.That(updates.Count(), Is.EqualTo(3));

                    updates = service.GetUpdates().PublishedWithinTimeRange(startDate, startDate.AddDays(2));

                    Assert.That(updates.Count(), Is.EqualTo(4));                    
                });
        }

        // ***** ***** ***** ***** ***** 
        // *****  
        // *****  T O P I C S    F I L T E R
        // *****  
        // ***** ***** ***** ***** ***** 
        [Test]
        public void Given_test_updates_When_TopicsFilter_is_assigned_Then_GetUpdates_returns_limited_list_of_updates()
        {
            Given(CreateUpdates);

            this.Then(service =>
            {

                ActivityFeedBuilder activityFeedBuilder = this.CreateActivityFeedBuilder("user1111", service);
                activityFeedBuilder.PaginationRequest = new PaginationRequest() { PageSize = 5 };
                activityFeedBuilder.SearchTerms = string.Empty;
                activityFeedBuilder.UserGroups = Enumerable.Empty<UserGroup>();
                activityFeedBuilder.TopicsFilter = new Topic[] { Topic.FromUserId("john"), Topic.FromUserId("sam") };
                PaginationStatus status;
                var updates = activityFeedBuilder.BuildActivityFeed(out status).ToList();
                Assert.That(updates.Count, Is.EqualTo(2));
                Assert.That(((Post)(updates[0].Content)).Text, Is.EqualTo("update4"));
            });
        }

        protected abstract ActivityFeedBuilder CreateActivityFeedBuilder(string subscriberId,
                                                                         IActivityFeedService activityFeedService);

    }    
}
    